{
 "metadata": {
  "name": "",
  "signature": "sha256:71011e6bff168d875e68c8dff32e53ec98371bc547667bd61e489712bfe2a926"
 },
 "nbformat": 3,
 "nbformat_minor": 0,
 "worksheets": [
  {
   "cells": [
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import numpy as np\n",
      "import torch\n",
      "import torch.autograd\n",
      "from torch.autograd import Variable\n",
      "import torch.nn.functional as F\n",
      "\n",
      "import matplotlib.pyplot as plt\n",
      "%matplotlib inline"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 46
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def get_linear_model(num_neurons):\n",
      "    return torch.nn.Sequential(\n",
      "        torch.nn.Linear(1, num_neurons),\n",
      "        torch.nn.ReLU(),\n",
      "        torch.nn.Linear(num_neurons, 1),\n",
      "    )"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 47
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def get_lognormal_rounded(size, max_value, mean=0.0, std=2.0):\n",
      "    \"\"\"\n",
      "    Create lognormal dataset, convert to ints, scale to make max value equal to max_value\n",
      "    \"\"\"\n",
      "    values = np.random.lognormal(mean, std, size)\n",
      "    current_max_val = values.max()\n",
      "    scale_factor = max_value / current_max_val\n",
      "    values *= scale_factor\n",
      "    values = np.round(values)\n",
      "    values.sort()\n",
      "    return values"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 48
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "def get_batch(batch_size=16):\n",
      "    labels = np.random.choice(dataset.shape[0], batch_size)\n",
      "    values = dataset[labels]\n",
      "    return (values, labels)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 49
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "import time"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 275
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "batch_size = 32\n",
      "num_neurons = 16\n",
      "learning_rate = 0.009\n",
      "num_epoch = 10000\n",
      "dataset_size = 100000\n",
      "max_value = 1e5\n",
      "dataset = get_lognormal_rounded(dataset_size, max_value)\n",
      "\n",
      "model = get_linear_model(num_neurons)\n",
      "optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)\n",
      "\n",
      "losses = []\n",
      "\n",
      "start = time.time()\n",
      "for epoch in range(num_epoch):\n",
      "    batch_x, batch_y = get_batch(batch_size)\n",
      "    \n",
      "    batch_x = torch.unsqueeze(Variable(torch.Tensor(batch_x)), 1)\n",
      "    batch_y = torch.unsqueeze(Variable(torch.Tensor(batch_y)), 1)\n",
      "    \n",
      "    result = model(batch_x) * dataset_size\n",
      "    \n",
      "    output = F.smooth_l1_loss(result, batch_y)\n",
      "    #output = F.mse_loss(result, batch_y)\n",
      "    loss = output.data[0]\n",
      "\n",
      "    losses.append(loss)\n",
      "\n",
      "    optimizer.zero_grad()\n",
      "    output.backward()\n",
      "    optimizer.step()\n",
      "    \n",
      "end = time.time()\n",
      "\n",
      "duration = end - start\n",
      "\n",
      "print(duration)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "output_type": "stream",
       "stream": "stdout",
       "text": [
        "3.84709405899\n"
       ]
      }
     ],
     "prompt_number": 402
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "plt.plot(losses)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "pyout",
       "prompt_number": 403,
       "text": [
        "[<matplotlib.lines.Line2D at 0x7f4284ee2510>]"
       ]
      },
      {
       "metadata": {},
       "output_type": "display_data",
       "png": "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\n",
       "text": [
        "<matplotlib.figure.Figure at 0x7f4286faa410>"
       ]
      }
     ],
     "prompt_number": 403
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "batch_x, batch_y = get_batch()\n",
      "\n",
      "batch_x = torch.unsqueeze(Variable(torch.Tensor(batch_x)), 1)\n",
      "batch_y = torch.unsqueeze(Variable(torch.Tensor(batch_y)), 1)\n",
      "\n",
      "result = model(batch_x) * dataset_size"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [],
     "prompt_number": 404
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [
      "if True:\n",
      "    cpp_loss_data_path = \"/home/ben/software/learned_indices/cmake-build-debug/loss.csv\"\n",
      "\n",
      "    data = open(cpp_loss_data_path).read().split(\"\\n\")\n",
      "    data = [row.split(\",\") for row in data]\n",
      "    data = [(int(row[0]), float(row[1])) for row in data if len(row) > 1]\n",
      "    losses = np.array(data)\n",
      "    plt.plot(losses[:, 1])\n",
      "    plt.ylim(0, 1e5)"
     ],
     "language": "python",
     "metadata": {},
     "outputs": [
      {
       "metadata": {},
       "output_type": "display_data",
       "png": "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\ngg==\n",
       "text": [
        "<matplotlib.figure.Figure at 0x7f42851250d0>"
       ]
      }
     ],
     "prompt_number": 405
    },
    {
     "cell_type": "code",
     "collapsed": false,
     "input": [],
     "language": "python",
     "metadata": {},
     "outputs": []
    }
   ],
   "metadata": {}
  }
 ]
}